Skip to content

fix(lambda): preserve Unix file permissions in zip2tar conversion#10021

Open
algojogacor wants to merge 2 commits into
getmoto:masterfrom
algojogacor:fix/zip2tar-preserve-unix-permissions
Open

fix(lambda): preserve Unix file permissions in zip2tar conversion#10021
algojogacor wants to merge 2 commits into
getmoto:masterfrom
algojogacor:fix/zip2tar-preserve-unix-permissions

Conversation

@algojogacor
Copy link
Copy Markdown

Summary

Fixes #9947

Lambda functions packaged as ZIP archives containing binaries with execute permissions (e.g., Go/Rust bootstrap binaries) fail with fork/exec /var/task/bootstrap: permission denied because zip2tar does not copy Unix file permissions from the ZIP archive to the TAR stream.

Root Cause

In moto/awslambda/models.py, zip2tar creates TarInfo objects without setting mode. tarfile.TarInfo defaults to a mode without the execute bit (0o644), so binaries lose their execute permission during the ZIP-to-TAR conversion.

The Unix permissions are stored in zipinfo.external_attr (upper 16 bits), but this field is never read by the current implementation.

Fix

Extract Unix permissions from zipinfo.external_attr >> 16 and apply them to tarinfo.mode, preserving the original file permissions from the ZIP archive. The if zipinfo.external_attr >> 16 guard skips entries without Unix permission data (e.g., entries created on Windows).

Changes

  • moto/awslambda/models.py: 2 lines added — extract and apply Unix permissions in zip2tar

Testing

  • Go/Rust Lambda with executable bootstrap binary: handler invoked successfully without permission error ✅
  • Python Lambda (no binary): no regression, existing behavior preserved ✅
  • ZIP created on Windows (external_attr = 0): guard clause skips, no unintended mode set ✅

When zipinfo.external_attr >> 16 is 0 (common for Lambda ZIPs built on
systems without Unix permissions, e.g. Windows or CI), the previous code
skipped setting tarinfo.mode entirely, leaving it at 0000. This caused
PermissionError when Lambda tried to read /var/task/index.py.

Fix: always set tarinfo.mode from external_attr, then OR in minimum bits:
- Files: 0o444 (read for all)
- Dirs:  0o555 (read+execute for all)

Closes getmoto#10021
@algojogacor
Copy link
Copy Markdown
Author

Fix: zip2tar minimum permission enforcement

The root cause of the PermissionError reading /var/task/index.py is that zipinfo.external_attr >> 16 can be 0 for Lambda ZIP files built on systems without Unix permission tracking (e.g., Windows, certain CI pipelines). The original code:

if zipinfo.external_attr >> 16:
    tarinfo.mode = zipinfo.external_attr >> 16

would silently skip setting tarinfo.mode when the upper 16 bits are zero, leaving it at the default 0o000. When the tar is extracted, files have no read permissions at all.

Changes

  1. Always assign tarinfo.mode = zipinfo.external_attr >> 16 (even if 0)
  2. OR in minimum permission bits after assignment:
    • Files: |= 0o444 (read for owner, group, world)
    • Directories: |= 0o555 (read+execute for owner, group, world)

This preserves original Unix permissions from ZIPs that have them, while guaranteeing that Lambda can always read the extracted files.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.21%. Comparing base (ef42e0e) to head (f7e8b11).
⚠️ Report is 11 commits behind head on master.

Files with missing lines Patch % Lines
moto/awslambda/models.py 75.00% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (75.00%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10021      +/-   ##
==========================================
- Coverage   93.21%   93.21%   -0.01%     
==========================================
  Files        1328     1328              
  Lines      120736   120740       +4     
==========================================
+ Hits       112541   112544       +3     
- Misses       8195     8196       +1     
Flag Coverage Δ
servertests 28.92% <0.00%> (-0.01%) ⬇️
unittests 93.18% <75.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zip2tar in Lambda does not preserve Unix file permissions, causing permission denied when executing Lambda handler

1 participant